-
Notifications
You must be signed in to change notification settings - Fork 112
Performance improvements to dual simplex: BFRT, hypersparsity, basis updates, primal infeasible list #192
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Other experiments included in this PR: 1) Bound strengthing on CPU for dual simplex. Note that this did not lead to an improvement on the NETLIB LP test set. 2) Attempt at O(N) bound-flipping ratio test using bucket sort. This is stil a work in progress. 3) Attempt to compute Farkas certificate when no entering variable found in dual simplex ratio test. This has not been verified yet. Note that the maros NETLIB problem is classifed as infeasible with the list of primal infeasibilites and the updated pricing. As far as I can tell this is due to different choices for leaving variables in the pricing---that have the same score. To try to handle no entering variables better, I tried to remove the dual perturbation and reset the steepest edge. This allows me to continue on maros. But ultimately the problem is still classified as infeasible.
…nd greenbeb as well. Farkas works on 17/24 NETLIB infeasible problems
|
/ok to test efb768c |
|
/ok to test 3905665 |
KyleFromNVIDIA
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved trivial CMake changes
…variable. Allocate timer to ftran
|
/ok to test 2230fbc |
aliceb-nv
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for the awesome work Chris!
Just a few minor comments :)
cpp/src/dual_simplex/phase2.cpp
Outdated
|
|
||
| phase2::reset_basis_mark(basic_list, nonbasic_list, basic_mark, nonbasic_mark); | ||
|
|
||
| std::vector<bool> bounded_variables(n, false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
std::vector<bool> tends to be somewhat slower (as it's implemented through a bitmap), I'm not sure if this is anything close to a hotspot but for these use cases a std::vector or std::vector<uint8_t> work better
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes. Good catch. The bitmap might slow down the access. I switched to uint8_t as suggested.
| assert(row_permutation_.size() == m); | ||
| assert(rhs.n == m); | ||
| assert(solution.n == m); | ||
| assert(Lsol.n == m); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those asserts will only be compiled when building in debug mode which we rarely ever do, we might want to use cuopt_assert instead (which is controlled by the "-a" flag in ./build.sh)
cpp/src/dual_simplex/phase2.cpp
Outdated
| std::vector<i_t>& infeasibility_indices, | ||
| f_t& primal_inf) | ||
| { | ||
| const f_t now_feasible = std::numeric_limits<f_t>::denorm_min(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are denormals useful here? I think double should have enough precision, computations involving denormals usually imply a performance hit
As an aside: we might want to measure the performance/quality impact of flushing denormals to zero at some point for the CPU code, just in case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not using the denormals for computation here. I was using this small value as a marker in the squared_infeasibilities array. If squared_infeasibilites[j] == now_feasible, than variable j has become feasible, and it can be removed from the infeasibility_indicies list. I think it is fine to just set the value to 0.0.
cpp/src/dual_simplex/phase2.cpp
Outdated
| void clean_up_infeasibilities(std::vector<f_t>& squared_infeasibilities, | ||
| std::vector<i_t>& infeasibility_indices) | ||
| { | ||
| const f_t now_feasible = std::numeric_limits<f_t>::denorm_min(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed denormals. See above.
| std::vector<f_t> my_delta_y; | ||
| delta_y_sparse.to_dense(my_delta_y); | ||
|
|
||
| // TODO(CMM): Do I use the perturbed or unperturbed objective? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Has this TODO been addressed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, no. I'm still not sure which to use here. Right now the objective value is just for printing in the logs. So it doesn't affect the solution.
| // TODO(CMM): Do I also need to update the objective due to the bound flips? | ||
| // TODO(CMM): I'm using the unperturbed objective here, should this be the perturbed objective? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Has this TODO been addressed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, no. Similar to the above I'm not sure what to do here. Luckily, it only affects the objective in the logs.
| for (i_t k = 0; k < i.size() - 1; ++k) { | ||
| if (i[k] > i[k + 1]) { printf("Sort error %d %d\n", i[k], i[k + 1]); } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just another tiny FYI: std::is_sorted is useful for this (in asserts and similar)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. I switched to std::is_sorted.
|
/ok to test 0c4459e |
aliceb-nv
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved! Thanks a lot for the great work Chris!
|
This is not critical but is highly, highly desirable from a perception basis |
|
/ok to test a939cf1 |
|
/ok to test 458e1dd |
|
/ok to test 9dc4329 |
|
/ok to test 7144d51 |
|
/merge |
This PR contains multiple performance improvements to the dual simplex code including:
New or existing test cover these changes. No changes in documentation are necessary.